package com.longrise.filedownloader;

import android.content.Context;
import android.os.Handler;
import android.os.Message;

import com.longrise.filedownloader.db.DBDAO;
import com.longrise.filedownloader.db.DownLoadStatusConstants;
import com.longrise.filedownloader.db.SqlDownloadBean;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Created by xkj on 16/4/12.
 * 下载类
 */
public class DownLoader {
    private static final String TAG = "DownLoader";


    private final int TASK_STOP = 1;
    private final int TASK_PROGESS = 2;
    private final int TASK_ERROR = 3;
    private final int TASK_SUCCESS = 4;
    private final int NOFREE_SPACE = 5;

    private final Context mContext;
    private final ThreadPoolExecutor mThreadPoll;
    private final SqlDownloadBean mSqlDownloadBean;
    private DownloadTask mDownloadTask;
    private int downloadtimes = 0;//当前尝试请求的次数
    private int maxdownloadtimes = 3;//失败重新请求次数
    private long fileSize = 0;//文件总大小
    private long mDownloadSize; //文件已经下载的大小
    /**
     * 标识服务器是否支持断点续传
     */
    private boolean isSupportBreakpoint = true;

    private String mFileName; //当前下载文件文件名称

    private String mFilePath; //文件路径

    private String mTempFilePath; //缓存文件路径
    private String mUrl;
    private OnFileDownloadStatusListener mListener;
    private OnDownloadFinishListener mFinishListener; //下载错误或者完成的监听
    private DBDAO mDao;
    private final DownloadFileInfo mDownloadFileInfo;


    public DownLoader(Context context, ThreadPoolExecutor poll, SqlDownloadBean sqlDownloadBean) {
        this.mContext = context;
        this.mThreadPoll = poll;
        this.mSqlDownloadBean = sqlDownloadBean;
        mDownloadFileInfo = new DownloadFileInfo();
        init();
    }

    private void init() {
        fileSize = mSqlDownloadBean.getFileSize();
        mDownloadSize = mSqlDownloadBean.getDownloadSize();
        mFileName = mSqlDownloadBean.getFileName();
        mFilePath = mSqlDownloadBean.getFilePath();
        mTempFilePath = mSqlDownloadBean.getTempFilePath();
        if(mTempFilePath==null){
            mTempFilePath = mFilePath + ".tmp";
        }
        mUrl = mSqlDownloadBean.getUrl();
        mDao = new DBDAO(mContext);
    }

    public String getUrl() {
        return mUrl;
    }

    public void setOnFileDownloadStatusListener(OnFileDownloadStatusListener listener) {
        this.mListener = listener;
    }

    /**
     * 开始下载
     *
     * @param listener
     */
    public void start(OnDownloadFinishListener listener) {
        this.mFinishListener = listener;
        if (mDownloadTask == null) {
            downloadtimes = 0;
            mDownloadTask = new DownloadTask();
            mThreadPoll.execute(mDownloadTask);
            onProgressNotice();
        }else{
            downloadtimes=0;
            mThreadPoll.execute(mDownloadTask);
            onProgressNotice();
        }
    }

    /**
     * 暂停下载
     */
    public void stop() {
        if (mDownloadTask != null) {
            mDownloadTask.stopDownLoad();
        }else{
            stopNotice();
        }
    }

    /**
     * 删除下载
     */
    public void delete(){
        if(mDownloadTask!=null){
            mDownloadTask.stopDownLoad();
        }
        File tempFile = new File(mTempFilePath);
        if(tempFile.exists()){
           tempFile.delete();
        }
        File downloadedFile = new File(mFilePath);
        if(downloadedFile.exists()){
            downloadedFile.delete();
        }
    }


    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == TASK_STOP) { //停止下载
                stopNotice();
            } else if (msg.what == TASK_PROGESS) { //正在下载
                onProgressNotice();
            } else if (msg.what == TASK_ERROR) { //下载出错
                errorNotice();
            } else if (msg.what == TASK_SUCCESS) { //下载完成
                //calculateMD5();
                successNotice();
            } else if(msg.what == NOFREE_SPACE ){ //没有剩余空间
                showNoFreeBufferSpace();
            }
        }
    };


    /**
     * 等待下载
     */
    public void waitNotice() {
        mSqlDownloadBean.setDownloadStatus(DownLoadStatusConstants.WAITTING);
        updateDownloadInfo();
        saveSqlDownloadInfo();
        if(mListener!=null){
            mListener.onFileDownloadStatusWaiting(mDownloadFileInfo);
        }
    }

    /**
     * 停止下载通知
     */
    private void stopNotice() {
        mSqlDownloadBean.setDownloadStatus(DownLoadStatusConstants.PAUSE);
        updateDownloadInfo();
        saveSqlDownloadInfo();
        if (mListener != null) {
            mListener.onFileDownloadStatusPaused(mDownloadFileInfo);
        }
        if(mDownloadTask!=null){
            mThreadPoll.remove(mDownloadTask);
            mDownloadTask = null;
        }
    }

    /**
     * 正在下载的通知
     */
    private void onProgressNotice() {
        mSqlDownloadBean.setDownloadStatus(DownLoadStatusConstants.DOWNLOADING);
        updateDownloadInfo();
        saveSqlDownloadInfo();
        if (mListener != null) {
            mListener.onFileDownloadStatusDownloading(mDownloadFileInfo);
        }
    }

    /**
     * 下载出错的通知
     */
    private void errorNotice() {
        mSqlDownloadBean.setDownloadStatus(DownLoadStatusConstants.FAIL);
        updateDownloadInfo();
        saveSqlDownloadInfo();
        if (mListener != null) {
            mListener.onFileDownloadStatusFailed(mDownloadFileInfo);
        }
        if (mFinishListener != null) {
            mFinishListener.onError(this);
        }
        if(mDownloadTask!=null){
            mThreadPoll.remove(mDownloadTask);
            mDownloadTask = null;
        }
    }

    /**
     * 没有更多的缓存空间
     */
    private void showNoFreeBufferSpace(){
        if(mFinishListener!=null){
            mFinishListener.onNoFreeBufferSpace(this);
        }
    }

    /**
     * 下载成功的通知
     */
    private void successNotice() {
        mSqlDownloadBean.setDownloadStatus(DownLoadStatusConstants.SUCCESS);
        updateDownloadInfo();
        saveSqlDownloadInfo();
        if (mListener != null) {
            mListener.onFileDownloadStatusCompleted(mDownloadFileInfo);
        }
        if (mFinishListener != null) {
            mFinishListener.onSuccess(this);
        }
        if(mDownloadTask!=null){
            mThreadPoll.remove(mDownloadTask);
            mDownloadTask = null;
        }
    }

    /**
     * (保存下载信息至数据库)
     */
    private void saveSqlDownloadInfo() {
        if (isSupportBreakpoint) {
            mSqlDownloadBean.setDownloadSize(mDownloadSize);
            mDao.saveDownloadInf(mSqlDownloadBean);
        }
    }

    /**
     * 更新下载信息
     */
    private void updateDownloadInfo() {
        mDownloadFileInfo.setDownloadSize(mDownloadSize);
        mDownloadFileInfo.setFileName(mFileName);
        mDownloadFileInfo.setFileSize(fileSize);
        if (fileSize == 0) {
            mDownloadFileInfo.setProgress(0);
        } else {
            mDownloadFileInfo.setProgress((int) (mDownloadSize * 100 / fileSize));
        }
        mDownloadFileInfo.setFilePath(mFilePath);
        mDownloadFileInfo.setUrl(mUrl);
    }

    /**
     * 创建缓存文件夹
     */
    private void createFolder() {
        File file = new File(mFilePath);
        File parentFile = file.getParentFile();
        if (!parentFile.exists()) {
            boolean mkdirs = parentFile.mkdirs();

        }
    }

    /**
     * 重命名文件
     *
     * @return 文件是否重命名成功
     */
    private boolean RenameFile() {
        File newFile = new File(mFilePath);
        if (newFile.exists()) {
            newFile.delete();
        }
        File oldFile = new File(mTempFilePath);
        createFolder();
        return oldFile.renameTo(newFile);
    }

    /**
     * 下载任务
     */
    class DownloadTask implements Runnable {

        private boolean isdownloading;
        private URL url;
        private RandomAccessFile localFile;
        private HttpURLConnection urlConn;
        private InputStream inputStream;
        private int progress = -1;

        public DownloadTask() {
            isdownloading = true;
        }

        @Override
        public void run() {
            while (downloadtimes < maxdownloadtimes) { //做3次请求的尝试
                try {
                    if (mDownloadSize == fileSize && fileSize > 0) {
                        File file = new File(mFilePath); //本地文件被删除了就重新下载
                        if(file.exists()){
                            Message msg = new Message();
                            msg.what = TASK_SUCCESS;
                            handler.sendMessage(msg);
                            downloadtimes = maxdownloadtimes;
                            mDownloadTask = null;
                            return;
                        }

                    }
                    url = new URL(mSqlDownloadBean.getUrl());
                    urlConn = (HttpURLConnection) url.openConnection();
                    urlConn.setConnectTimeout(5000);
                    urlConn.setReadTimeout(10000);
                    if (fileSize < 1) {//第一次下载，初始化
                        openConnention();
                    } else {
                        if (new File(mTempFilePath).exists()) {
                            localFile = new RandomAccessFile(mTempFilePath, "rwd");
                            localFile.seek(mDownloadSize);
                            urlConn.setRequestProperty("Range", "bytes=" + mDownloadSize + "-");
                        } else {
                            fileSize = 0;
                            mDownloadSize = 0;
                            openConnention();
                        }
                    }
                    //判断手机内存是否能装的下视频
                    boolean canStore = ExternalStorageUtils.isCanStore(fileSize);
                    if(!canStore){
                        Message message = handler.obtainMessage();
                        message.what = NOFREE_SPACE;
                        handler.sendMessage(message);
                        //如果内存不足 就通知用户内存不足
                        return;
                    }

                    inputStream = urlConn.getInputStream();
                    byte[] buffer = new byte[1024 * 4];
                    int length = -1;
                    while ((length = inputStream.read(buffer)) != -1 && isdownloading) {
                        localFile.write(buffer, 0, length);
                        mDownloadSize += length;
                        int nowProgress = (int) ((100 * mDownloadSize) / fileSize);
                        if (nowProgress > progress) {
                            progress = nowProgress;
                            handler.sendEmptyMessage(TASK_PROGESS);
                        }
                      //  Thread.sleep(20); 可以用来限速  比如你的每次读取都是 byte[1024] 也就是1KB，如果要控制上传速度是 10KB/s，那么粗略点的控制方式就是每隔100ms读取一次1KB。
                    }
                    //下载完了
                    if (mDownloadSize == fileSize) {

                        boolean renameResult = RenameFile();
                        if (renameResult) {
                            handler.sendEmptyMessage(TASK_SUCCESS); //转移文件成功
                        } else {
                            handler.sendEmptyMessage(TASK_ERROR);//转移文件失败
                        }
                    }
                    downloadtimes = maxdownloadtimes;
                } catch (Exception e) {
                    if (isdownloading) {
                        if (isSupportBreakpoint) {
                            downloadtimes++;
                            if (downloadtimes >= maxdownloadtimes) {
                                handler.sendEmptyMessage(TASK_ERROR);
                            }
                        } else {
                            mDownloadSize = 0;
                            downloadtimes = maxdownloadtimes;
                            handler.sendEmptyMessage(TASK_ERROR);
                        }

                    } else {
                        downloadtimes = maxdownloadtimes;
                    }
                    e.printStackTrace();
                } finally {
                    try {
                        if (urlConn != null) {
                            urlConn.disconnect();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    try {
                        if (inputStream != null) {
                            inputStream.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    try {
                        if (localFile != null) {
                            localFile.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        public void stopDownLoad() {
            isdownloading = false;
            downloadtimes = maxdownloadtimes;
            handler.sendEmptyMessage(TASK_STOP);
        }


        private void openConnention() throws Exception {
            long urlfilesize = urlConn.getContentLength();
            if (urlfilesize > 0) {
                createFolder();
                localFile = new RandomAccessFile(mTempFilePath, "rwd");
                mSqlDownloadBean.setFileSize(urlfilesize);
                fileSize = urlfilesize;
                if (isdownloading) {
                    Message msg = handler.obtainMessage();
                    msg.what = TASK_PROGESS;
                    handler.sendMessage(msg);
                }
            }
        }


    }
}
